/*
 * @(#)PerfectNumberParser.java    Jul 6, 2010
 *
 * Copyright 2009 Nyber Shanghai, Inc. All rights reserved.
 */

package com.lab.basic;

import java.util.ArrayList;
import java.util.List;

/**
 * 一个数如果恰好等于除它本身外的因子之和, 这个数就称为"完数", 也叫"完美数".
 * 
 * <ul>
 * 	<li>1 + 2 + 3 = 6</li>
 * 	<li>1 + 2 + 4 + 7 + 14 = 28</li>
 * 	<li>1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248 = 496</li>
 * 	<li>1 + 2 + 4 + 8 + 16 + 32 + 64 + 127 + 254 + 508 + 1016 + 2032 + 4064 = 8128</li>
 * </ul>
 *
 * @author nickevin@gmail.com
 * @version Jul 6, 2010 10:31:28 AM
 */

public class PerfectNumberParser {

	public Result parse(int number) {
		List<Integer> factors = getFactors(number);
		if (total(factors) == number) {
			return new Result(true, statement(factors, number));
		}

		return new Result(false);
	}

	private int total(List<Integer> factors) {
		int sum = 0;
		for (int n : factors) {
			sum += n;
		}

		return sum;
	}

	private List<Integer> getFactors(int number) {
		List<Integer> factors = new ArrayList<Integer>(32) {
			{
				add(1);
			}
		};

		double _number = Math.sqrt(number);
		for (int i = 2; i < _number; i++) {
			if (number % i == 0) {
				factors.add(i);
				if (number / i != i) {
					factors.add(number / i);
				}
			}
		}

		return factors;
	}

	private String statement(List<Integer> factors, Integer number) {
		StringBuilder sb = new StringBuilder();

		int size = factors.size();
		sb.append(factors.get(0));
		for (int idx = 1; idx < size; idx++) {
			sb.append(" + ");
			sb.append(factors.get(idx));
		}
		sb.append(" = ");

		return sb.append(number).toString();
	}

	static class Result {

		private boolean success;
		private String recognized = "It's not a perfect number.";

		public Result(boolean success) {
			this.success = success;
		}

		public Result(boolean success, String recognized) {
			this.success = success;
			this.recognized = recognized;
		}

		public String getRecognized() {
			return recognized;
		}

		public void setRecognized(String recognized) {
			this.recognized = recognized;
		}

		public boolean isSuccess() {
			return success;
		}

		public void setSuccess(boolean success) {
			this.success = success;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result
					+ (recognized == null ? 0 : recognized.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			final Result other = (Result) obj;
			if (recognized == null) {
				if (other.recognized != null) {
					return false;
				}
			} else if (!recognized.equals(other.recognized)) {
				return false;
			}
			return true;
		}

		@Override
		public String toString() {
			return new StringBuilder().append("succeeded: " + success).append(
					", recognized: " + recognized).toString();
		}

	}

	private PerfectNumberParser() {}

	static class SingletonHolder {
		static PerfectNumberParser instance = new PerfectNumberParser();
	}

	public static PerfectNumberParser getInstance() {
		return SingletonHolder.instance;
	}
}
